---
id: logout
title: Implementing the Logout Endpoint & UI
sidebar_label: Logout Endpoint
---

import useBaseUrl from '@docusaurus/useBaseUrl'
import Mermaid from '@theme/Mermaid'
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

:::note

Please read the [Logout Flow Documentation](../concepts/logout) first!

:::

In this document, you will learn how to implement the Logout Endpoint using our
ORY Hydra SDKs. The goal for this document is to have document this for multiple
programming languages. If you are an expert in one of these languages, your help
is highly appreciated in improving these docs!

## Implementing the Logout HTML Form

:::note

The Logout HTML Form cannot be only a Single Page App (Client-side browser
application) or a Mobile App! There has to be a server-side component with access
to ORY Hydra's Admin Endpoint!

:::

<Tabs
  defaultValue="ui"
  values={[
    {label: 'UI', value: 'ui'},
    {label: 'NodeJS', value: 'node'},
    {label: 'HTML Example', value: 'html'},
  ]}>
<TabItem value="ui">
<img src={useBaseUrl('/img/docs/logout-endpoint.png')}/>
</TabItem>
<TabItem value="node">

:::note

Check out our
[reference implementation](https://github.com/ory/hydra-login-consent-node) of
this endpoint!

:::

```typescript title="routes/logout.ts"
// This example uses ExpressJS
import express from 'express'
import url from 'url'
import csrf from 'csurf'
import { AdminApi } from '@oryd/hydra-client'

const hydraAdmin = new AdminApi(process.env.HYDRA_ADMIN_URL)

// Sets up csrf protection. Always do this when handling HTML forms!
const csrfProtection = csrf({ cookie: true })
const router = express.Router()

router.get('/', csrfProtection, (req, res, next) => {
  // Parses the URL query
  const query = url.parse(req.url, true).query

  // The challenge is used to fetch information about the logout request from ORY Hydra.
  const challenge = String(query.logout_challenge)
  if (!challenge) {
    next(new Error('Expected a logout challenge to be set but received none.'))
    return
  }

  hydraAdmin
    .getLogoutRequest(challenge)
    // This will be called if the HTTP request was successful
    .then(({ body }) => {
      // Here we have access to e.g. response.subject, response.sid, ...

      // The most secure way to perform a logout request is by asking the user if he/she really want to log out.
      res.render('logout', {
        csrfToken: req.csrfToken(),
        challenge: challenge
      })
    })
    // This will handle any error that happens when making HTTP calls to hydra
    .catch(next)
})
```

</TabItem>
<TabItem value="html">

```html
<form action="/logout" method="POST">
  <input type="hidden" name="_csrf" value="{{ .csrfToken }}" />
  <input type="hidden" name="challenge" value="{{ .challenge }}" />
  <input type="submit" id="accept" value="Yes" />
  <input type="submit" id="reject" value="No" />
</form>
```

</TabItem>
</Tabs>

## Accepting Logout

<Tabs
  defaultValue="node"
  values={[
    {label: 'NodeJS', value: 'node'},
  ]}>
<TabItem value="node">

:::note

Check out our
[reference implementation](https://github.com/ory/hydra-login-consent-node) of
this endpoint!

:::

```typescript title="routes/logout.ts"
// This is the endpoint the user ends up at once she/he inserts their password and username and hits "Log in".
router.post('/logout', csrfProtection, (req, res, next) => {
  // The user agreed to log out, let's accept the logout request.
  hydraAdmin
    .acceptLogoutRequest(challenge)
    .then(({ body }) => {
      // All we need to do now is to redirect the user back to hydra!
      res.redirect(String(body.redirectTo))
    })
    // This will handle any error that happens when making HTTP calls to hydra
    .catch(next)
})
```

</TabItem>
</Tabs>

## Rejecting Logout

<Tabs
  defaultValue="node"
  values={[
    {label: 'NodeJS', value: 'node'},
  ]}>
<TabItem value="node">

:::note

Check out our
[reference implementation](https://github.com/ory/hydra-login-consent-node) of
this endpoint!

:::

```typescript title="routes/logout.ts"
// This is the endpoint the user ends up at once she/he inserts their password and username and hits "Log in".
router.post('/logout', csrfProtection, (req, res, next) => {
  return (
    hydraAdmin
      .rejectLogoutRequest(challenge)
      .then(() => {
        // The user did not want to log out. Let's redirect him back somewhere or do something else.
        res.redirect('https://www.ory.sh/')
      })
      // This will handle any error that happens when making HTTP calls to hydra
      .catch(next)
  )
})
```

</TabItem>
</Tabs>
